package com.luxus.ui;

import com.android.camera.one.FaceDetectInfo;
import com.android.camera.one.OneCamera.Facing;
import com.luxus.cdcam.R;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.RectF;
import android.hardware.camera2.CameraCharacteristics;
import android.util.AttributeSet;
import android.view.View;

public class PreviewOverlay extends View {

	private static final int SHOW_GRID = 0x01;
	private static final int SHOW_FACE = 0x02;
	private static final int SHOW_INFO = 0x04;
	private int mColor;
    private int mColor2;
    private Paint mPaint;
    private Paint mPaint2;
    
    private Facing mFacing = Facing.BACK;
    private int mOrientation = 0;
    
    private boolean mShowGyroGrid;
    private float mFovLargeDegrees;
    private float mFovSmallDegrees;
    float[] mAngles = new float[2];
    
    private FaceDetectInfo[] mFaceInfos;
    
	public PreviewOverlay(Context context, AttributeSet attrs) {
		super(context, attrs);
		Resources res = getResources();
        mColor = res.getColor(R.color.hud_color);
        mPaint = new Paint();
        mPaint.setColor(mColor);
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(res.getDimension(R.dimen.hud_stroke));

        mColor2 = res.getColor(R.color.face_color);
        mPaint2 = new Paint();
        mPaint2.setColor(mColor2);
        mPaint2.setAntiAlias(true);
        mPaint2.setStyle(Paint.Style.STROKE);
        mPaint2.setStrokeWidth(res.getDimension(R.dimen.face_circle_stroke));
	}

	public void setFacingAndOrientation(Facing facing, int orientation) {
        mFacing = facing;
        mOrientation = orientation;
    }
	
	public void showGyroGrid(boolean show) {
        mShowGyroGrid = show;
        if (show) {
        	this.setVisibility(VISIBLE);
        }
        invalidate();
    }
	
	public void showFaceInfo(FaceDetectInfo[] faces) {
		mFaceInfos = faces;
		if (faces != null) {
			this.setVisibility(VISIBLE);
		}
		invalidate();
	}
	
	public void setFieldOfView(float fovLargeDegrees, float fovSmallDegrees) {
        mFovLargeDegrees = fovLargeDegrees;
        mFovSmallDegrees = fovSmallDegrees;
    }
	
	public void setGyroAngles(float[] angles) {
        // Rotate gyro coordinates to match camera orientation
        // Gyro data is always presented in the device native coordinate system, which
        // is either portrait or landscape depending on device.
        // (http://developer.android.com/reference/android/hardware/SensorEvent.html)
        // DevCamera locks itself to portrait, and the camera sensor long edge is always aligned
        // with the long edge of the device.
        // mOrientation is the relative orientation of the camera sensor and the device native
        // orientation, so it can be used to decide if the gyro data is meant to be interpreted
        // in landscape or portrait and flip coordinates/sign accordingly.
        // Additionally, front-facing cameras are mirrored, so an additional sign flip is needed.
        switch (mOrientation) {
            case 0:
                mAngles[1] = -angles[0];
                mAngles[0] = angles[1];
                break;
            case 90:
                mAngles[0] = angles[0];
                mAngles[1] = angles[1];
                break;
            case 180:
                mAngles[1] = -angles[0];
                mAngles[0] = angles[1];
                break;
            case 270:
                mAngles[0] = angles[0];
                mAngles[1] = angles[1];
                break;
        }
        if (mFacing != Facing.BACK) {
            // Reverse sensor readout for front/external facing cameras
            mAngles[0] = -mAngles[0];
            mAngles[1] = -mAngles[1];
        }
        invalidate();
    }
	
	@Override
    protected void onDraw(Canvas canvas) {
		float previewW = this.getWidth();
        float previewH = this.getHeight();
        
        if (mShowGyroGrid) {
        	float x1, x2, y1, y2;
        	
        	float focalLengthH = 0.5f * previewH / (float) Math.tan(Math.toRadians(mFovLargeDegrees) * 0.5);
            float focalLengthW = 0.5f * previewW / (float) Math.tan(Math.toRadians(mFovSmallDegrees) * 0.5);
            final double ANGLE_STEP = (float) Math.toRadians(10f);
            // Draw horizontal lines, with 10 degree spacing.
            double phase1 = mAngles[0] % ANGLE_STEP;
            for (double i = -5 * ANGLE_STEP + phase1; i < 5 * ANGLE_STEP; i += ANGLE_STEP) {
                x1 = 0;
                x2 = previewW;
                y1 = y2 = previewH / 2 + focalLengthH * (float) Math.tan(i);
                canvas.drawLine(x1, y1, x2, y2, mPaint);
            }
            // Draw vertical lines, with 10 degree spacing.
            double phase2 = mAngles[1] % ANGLE_STEP;
            for (double i = -5 * ANGLE_STEP + phase2; i < 5 * ANGLE_STEP; i += ANGLE_STEP) {
                x1 = x2 = previewW / 2 + focalLengthW * (float) Math.tan(i);
                y1 = 0;
                y2 = previewH;
                canvas.drawLine(x1, y1, x2, y2, mPaint);
            }
        }
        
        if (mFaceInfos != null) {
        	for (FaceDetectInfo face : mFaceInfos) {
        		RectF r1 = face.getBounds();
                float newY = r1.centerX() * previewH;
                float newX = (1 - r1.centerY()) * previewW;
                float dY = r1.width() * previewH;
                float dX = dY;//r1.height() * previewW;
                float dP = (dX + dY) * 0.045f;
                RectF newR1 = new RectF(newX - dX * 0.5f, newY - dY * 0.5f, newX + dX * 0.5f, newY + dY * 0.5f);
                canvas.drawRoundRect(newR1, dP, dP, mPaint2);

                PointF[] p = new PointF[3];
                p[0] = face.getLeftEye();
                p[1] = face.getRightEye();
                p[2] = face.getMouth();

                for (int j = 0; j < 3; j++) {
                    if (p[j] == null) {
                        continue;
                    }
                    newY = p[j].x * previewH;
                    newX = (1 - p[j].y) * previewW;
                    canvas.drawCircle(newX, newY, dP, mPaint2);
                }
        	}
        }
        
        super.onDraw(canvas);
	}
}
